(function(window){

    /** ------------------------- data ------------------------ */

    var u = {};
    const keyWidgetVersion = 'widgetVersion';
    const widgetZipPath = 'fs://widget.zip';
    const appAPKPath = 'fs://download/update_demo.apk';
    const appUpdateError = {
        'unknown'               : { state: 1,  msg: '未知操作系统!!!' },
        'appPara'               : { state: 5,  msg: '[url] 不存在，请检查参数!!!' },
        'widgetPara'            : { state: 4,  msg: '[url] or [widgetVersion] 不存在，请检查参数!!!' },
        'download'              : { state: 6,  msg: '下载失败!!!' },
        'unzip'                 : { state: 2,  msg: '解压失败!!!' },
        'delete'                : { state: 3,  msg: '删除Widget文件夹失败!!!' },
        'fileNotExist'          : { state: 7,  msg: '文件不存在!!!' },
        'noRemoteAppVersion'    : { state: 8,  msg: '没有更新的appVersion' },
        'noRemoteWidgetVersion' : { state: 9,  msg: '没有更新的widgetVersion' },
        'noUpdate'              : { state: 10, msg: '没有App与Widget需要更新' },
        'cancelUpdate'          : { state: 11, msg: '取消更新' },
    }
    const downloadAPKTitle = "正在下载apk";
    const downloadWidgetTitle = "正在下载Widget";
    const downloadMessage = "下载中...";

    /** ------------------------- data ------------------------ */

    /** ------------------------- method ----------------------- */

    /**
     * update widget progress
     * @param {*} widgetMetaData 
     * @param {*} callback 
     */
    function updateWidgetPromise(widgetMetaData, callback) {
        var version = widgetMetaData.version
        openProgressPromise(downloadWidgetTitle, downloadMessage)
        .then(function(ret) {
            console.log(JSON.stringify(ret));
            return downloadWidgetZipPromise(widgetMetaData, callback);
        })
        .then(function(ret) {
            console.log(JSON.stringify(ret));
            return unzipWidgetPromise(widgetMetaData, callback);
        })
        .then(function(ret) {
            console.log(JSON.stringify(ret));
            return checkFileExistPromise(widgetZipPath, callback);
        })
        .then(function(ret) {
            console.log(JSON.stringify(ret));
            if (ret.exist === 'YES') {
                return deleteFilePromise(widgetZipPath, callback);
            }
        })
        .then(function(ret) {
            if (ret) {
                console.log(JSON.stringify(ret));
            }
            // add widget profile
            return addWidgetProfilePromise({
                widgetVersion: version
            }, callback);
        })
        .then(function(ret) {
            console.log(JSON.stringify(ret));
            return alertRebootPromise(callback);
        })
        .then(function(ret) {
            console.log(JSON.stringify(ret));
            console.log("start reboot...");
            api.rebootApp();
        })
        .finally(function() {
            console.log('update widget process completed...');
        });
    }

    /**
     * Update App
     * @param {*} appMetaData 
     * @param {*} callback 
     */
    function updateAppPromise(appMetaData, callback) {
        if (!appMetaData || !appMetaData.url) {
            errCallbackHandler(appUpdateError.appPara, callback);
        }

        if (api.systemType == "android") {
            // updateAPK(appMetaData, callback);
            updateAPKPromise(appMetaData, callback);
        } else if (api.systemType == "ios") {
            // updateIPA(appMetaData, callback);
            updateIPAPromise(appMetaData, callback);
        } else {
            // unhandle system
            errCallbackHandler(appUpdateError.unknown, callback);
        }
    }

    /**
     * apk update workflow
     * @param {*} appMetaData 
     * @param {*} callback 
     */
     function updateAPKPromise(appMetaData, callback) {
        const widgetFolderPath = `${widgetDirectoryPath()}/widget`;
        openProgressPromise(downloadAPKTitle, downloadMessage)
        .then(function(ret) {
            console.log(JSON.stringify(ret));
            return checkFileExistPromise(appAPKPath, callback);
        })
        .then(function(ret) {
            console.log(JSON.stringify(ret));
            if (ret.exist === "YES") {
                return deleteFilePromise(appAPKPath, callback);
            }
        })
        .then(function(ret) {
            if (ret) {
                console.log(JSON.stringify(ret));
            }
            return downloadAPKPromise(appMetaData);
        })
        .then(function(ret) {
            console.log(JSON.stringify(ret));
            return checkFileExistPromise(widgetFolderPath, callback);
        })
        .then(function(ret) {
            console.log(JSON.stringify(ret));
            if (ret.exist === "YES") {
                return removeFolderPromise(widgetFolderPath, callback);
            }
        })
        .then(function(ret) {
            if (ret) {
                console.log(JSON.stringify(ret));
            }
            return deleteWidgetConfigPromise(callback);
        })
        .then(function(ret) {
            api.installApp({
                appUri : appAPKPath
            });
        })
        .catch(function(err) {
            errCallbackHandler(err, callback);
        })
        .finally(function() {
            console.log('update apk process completed...');
        });
    }

    /**
     * update ipa
     * @param {*} appMetaData 
     * @param {*} callback 
     */
    function updateIPAPromise(appMetaData, callback) {
        const widgetFolderPath = `${widgetDirectoryPath()}/widget`;
        checkFileExistPromise(widgetFolderPath, callback)
        .then(function(ret) {
            console.log(JSON.stringify(ret));
            if (ret.exist === "YES") {
                return removeFolderPromise(widgetFolderPath, callback);
            }
        })
        .then(function(ret) {
            if (ret) {
                console.log(JSON.stringify(ret));
            }
            return deleteWidgetConfigPromise(callback);
        })
        .then(function(ret) {
            api.installApp({
                appUri : appMetaData.url
            });
        })
        .catch(function(err) {
            errCallbackHandler(err, callback);
        })
        .finally(function() {
            console.log('update ipa process completed...');
        });
    }

    
    // ==================== Common Steps start ===============================
     
    /**
     * open Progress
     * @param {*} title 
     * @param {*} message 
     * @returns 
     */
    function openProgressPromise(title, message) {
        return new Promise(function(resolve, reject) {
            var UIActionProgress = api.require('UIActionProgress');
            UIActionProgress.open({
                maskBg: 'rgba(0,0,0,0.3)',
                styles: {
                    h: 120,
                    bg: '#fff',
                    border: {
                        size: 2,
                        color: '#4876FF'
                    },
                    title: {
                        size: 13,
                        color: '#000',
                        marginT: 10
                    },
                    msg: {
                        size: 12,
                        color: '#000',
                        marginT: 5
                    },
                    lable: {
                        size: 12,
                        color: '#696969',
                        marginB: 5
                    },
                    progressBar: {
                        size: 2,
                        normal: '#000',
                        active: '#4876FF',
                        marginB: 35,
                        margin: 5
                    }
                },
                data: {
                    title: title,
                    msg: message,
                    value: 0
                }
            },function(ret){
                if (ret.eventType === 'show') {
                    resolve({
                        'state' : 'success',
                        'progressRet' : ret
                    });
                }
                // if (ret.eventType === 'click') {
                //     console.log('点击了遮罩层')
                // }
                // if (ret.eventType === 'complete') {
                //     console.log('value值到100%')
                // }
            });
        });
    }

    /**
     * check widget zip exist
     * @param {*} para 
     * @param {*} callback 
     * @returns 
     */
    function checkFileExistPromise(path, callback) {
        return new Promise(function(resolve, reject) {
            if (checkFileExist(path, callback)) {
                resolve({
                    'exist' : 'YES'
                })
            } else {
                resolve({
                    'exist' : 'NO'
                })
            }
        });
    }

    /**
     * delete file
     * @param {*} path 
     * @param {*} callback 
     * @returns 
     */
    function deleteFilePromise(path, callback) {
        return new Promise(function(resolve, reject) {
            var fs = api.require('fs')
            const ret = fs.removeSync({
                path: path
            });
            if (ret.status) {
                resolve({
                    msg: `delete ${path} success`,
                    originRet: ret
                })
            } else {
                console.log(JSON.stringify(err))
                resolve({
                    msg: `delete ${path} failed`,
                    originRet: ret
                })
            }
        });
    }

    /**
     * alert reboot
     * @param {*} callback 
     * @returns 
     */
    function alertRebootPromise(callback) {
        return new Promise(function(resolve, reject) {
            api.alert({
                title: '更新完成',
                msg: 'reboot',
            }, function(ret, err) {
                resolve({
                    state: 0,
                    msg: 'tapped OK'
                })
            });
        });
    }

    /**
     * remove folder
     * @param {*} path 
     * @param {*} callback 
     * @returns 
     */
    function removeFolderPromise(path, callback) {
        return new Promise(function(resolve, reject) {
            var fs = api.require('fs')
            fs.rmdir({
                path:path
            }, function(ret, err){
                if (ret.status) {
                    resolve({
                        msg: `delete ${path} success!!`,
                        originRet: ret
                    });
                } else {
                    resolve({
                        msg: `delete ${path} failed!!`,
                        originRet: ret
                    });
                }
            })
        });
    }

    /**
     * delete widget config
     * @param {*} callback 
     * @returns 
     */
    function deleteWidgetConfigPromise(callback) {
        return new Promise(function(resolve, reject) {
            if (api.systemType === 'android') {
                // 删除 Preference(inc_package.xml)
                androidDeletePrefs();
            }

            // 删除 prefs widgetVersion
            api.removePrefs({
                key: keyWidgetVersion
            });

            resolve({
                "state" : 0,
                "msg": "delete widget config success!!"
            });
        });
    }

    // ==================== Common Steps end =================================
     
    // ==================== Widget Steps start =================================

    /**
     * download widget zip
     * @param {*} widgetMetaData 
     * @param {*} callback 
     * @returns 
     */
    function downloadWidgetZipPromise(widgetMetaData, callback) {
        return new Promise(function(resolve, reject) {
            api.download({
                url : widgetMetaData.url,
                savePath: widgetZipPath,
                report: true,
                cache: false
            }, function(ret, err) {
                if (ret && 0 == ret.state) {/* 下载进度 */
                    console.log("正在下载Widget" + ret.percent + "%");
                    setProgress('Widget下载', '正在下载...', ret.percent);
                }
                if (ret && 1 == ret.state) {/* 下载完成 */
                    // var savePath = ret.savePath;
                    // console.log(`save path = ${savePath}`)
                    // close progress
                    closeProgress();
                    // do next step
                    // unzipWidgetAndReboot(widgetMetaData, callback);
                    resolve(widgetMetaData);
                }
                if (ret && 2 == ret.state) {/* 下载失败 */
                    // close progress!!
                    closeProgress();
                    reject(appUpdateError.download)
                }
            });
        })
    }

    /**
     * unzip widget
     * @param {*} widgetMetaData 
     * @param {*} callback 
     * @returns 
     */
    function unzipWidgetPromise(widgetMetaData, callback) {
        return new Promise(function(resolve, reject) {
            api.showProgress({
                title: '解压Widget',
                text: '解压中...',
                modal: true
            });
            var zipModule = api.require('zipModule');
            var unzipPath = widgetDirectoryPath();
            zipModule.unzip({
                zipPath:widgetZipPath,
                unzipPath:unzipPath
            }, function(ret) {
                // console.log(`unzip path = ${unzipPath}`)
                api.hideProgress();
                if (ret.status === true) {
                    resolve(widgetMetaData)
                } else {
                    reject(appUpdateError.unzip);
                    // errCallbackHandler(appUpdateError.unzip, callback);
                }
            });
        });
    }

    /**
     * add widget profile
     * @param {*} metadata 
     * @param {*} callback 
     * @returns 
     */
    function addWidgetProfilePromise(metadata, callback) {
        return new Promise(function(resolve, reject) {
            // android extra step
            if (api.systemType == "android") {
                androidSetPrefs();
            }
            api.setPrefs({
                key: keyWidgetVersion,
                value: metadata.widgetVersion,
            })
            resolve({
                state: 0,
                msg: 'add widget profile success'
            })
        });
    }


    // ==================== Widget Steps end ====================================

    // ==================== App Steps start =================================

    /**
     * download APK
     * @param {*} appMetaData 
     * @returns 
     */
    function downloadAPKPromise(appMetaData) {
        return new Promise(function(resolve, reject) {
            console.log('准备下载APK...' + appMetaData.url);
            api.download({
                url : appMetaData.url,
                savePath: appAPKPath,
                report : true,
                cache: false
            }, function(ret, err) {
                if (ret && 0 == ret.state) {/* 下载进度 */
                    console.log("正在下载APK:" + ret.percent + "%");
                    setProgress('APK下载', '正在下载...', ret.percent);
                }
                if (ret && 1 == ret.state) {/* 下载完成 */
                    console.log('APK下载完成!');
                    closeProgress();
                    resolve({
                        'state' : 'success',
                        'downloadRet' : ret,
                        'savePath' : ret.savePath
                    });
                }
                if (ret && 2 == ret.state) {/* 下载失败 */
                    // close progress!!
                    closeProgress();
                    reject(appUpdateError.download)
                }
            });
        })
    }

    // ==================== App Steps end ===================================


    // =================== Other helper methods start =============================

    /**
     * 错误回调处理
     * @param {*} err 
     * @param {*} callback 
     */
    function errCallbackHandler(err, callback) {
        if (callback) {
            callback(err);
        } else {
            console.error(JSON.stringify(err));
            api.toast({
                msg: err.msg
            });
        }
    }

    /**
     * 设置进度条
     * @param {*} title 
     * @param {*} message 
     * @param {*} progress 
     */
    function setProgress(title, message, progress) {
        var UIActionProgress = api.require('UIActionProgress');
        UIActionProgress.setData({
            data: {
                title: title,
                msg: message,
                value: progress
            }
        });
    }

    /**
     * 关闭进度条
     */
    function closeProgress() {
        var UIActionProgress = api.require('UIActionProgress');
        UIActionProgress.close()
    }

    /** 
     * !important - 程序读取 Widget 的文件夹位置
     * @returns widget folder path
     */
    function widgetDirectoryPath() {
        var index = 0;
        var widgetDirPath = '';
        if (api.systemType == "android") {
            index = api.boxDir.indexOf('box');
            widgetDirPath = api.boxDir.slice(0, index);
            widgetDirPath = `${widgetDirPath}`;
        }
        else if (api.systemType == "ios") {
            index = api.boxDir.indexOf('Documents');
            widgetDirPath = api.boxDir.slice(0, index);
            widgetDirPath = `${widgetDirPath}Documents/APICloud/MainWidget`;
        }
        return widgetDirPath
    }

    /**
     * !important android 只有写入该 preference 才可读取 更新的Widget中代码
     */
    function androidSetPrefs() {
        var apiExtension = api.require('apiExtension')
        apiExtension.jSetPrefs({
            'prefName' : 'inc_package',
            'key' : 'version_name',
            'value': api.appVersion
        })
        apiExtension.jSetPrefs({
            'prefName' : 'inc_package',
            'key' : 'version_code',
            'value': apiExtension.versionNo()
        })
        apiExtension.jSetPrefs({
            'prefName' : 'inc_package',
            'key' : 'sub_version',
            'value': 1
        })
    }

    /**
     * ！important App更新时必须清空或删除 inc_package.xml
     */
    function androidDeletePrefs() {
        var apiExtension = api.require('apiExtension')
        const ret = apiExtension.jClearPrefs({
            'prefName' : 'inc_package'
        })

        console.log('clearing inc_package.xml...');
        if (ret) {
            console.log('clear inc_package.xml success!');
        } else {
            console.err('clear inc_package.xml failure!');
            console.error(JSON.stringify(ret));
        }
    }

    /**
     * !important - 检查文件是否存在
     * @param {*} path 
     * @returns 
     */
    function checkFileExist(path, callback) {
        var fs = api.require('fs');
        var ret = fs.existSync({
            path: path
        });
        if (ret.exist) {
            console.log(`发现 ${path}`);
            return true
        } else {
            console.warn(`${path} 不存在!!!`);
            return false
        }
    }

    // =================== Other helper methods end =============================


    /**
     * TODO: test check version
     * @param {*} metaData 
     * @param {*} callback 
     * @returns 
     */
    function checkVersionPromise(metaData, callback) {
        return new Promise(function(resolve, reject) {
            if (!metaData || !metaData.appVersion || !metaData.widgetVersion) {
                console.error('Please check [appVersion] and [widgetVersion]!!!');
                reject({ state: 111, msg: 'no [appVersion] and [widgetVersion] passed!!!' });
                return;
            }
            api.showProgress({
                title: '正在检查版本',
                text: '检查中...',
                modal: true
            });
            // api.ajax({
            //     url: 'http://192.168.1.101:3101/upLoad',
            //     method: 'post',
            //     headers: {
            //         'Content-Type': 'application/json;charset=utf-8'
            //     },
            //     data: {
            //         body: {
            //             name: 'haha'
            //         }
            //     }
            // }, function(ret, err) {
            //     if (ret) {
            //         api.alert({ msg: JSON.stringify(ret) });
            //     } else {
            //         api.alert({ msg: JSON.stringify(err) });
            //     }
            // });
            setTimeout(() => {
                api.hideProgress();
                const localAppVersion = api.appVersion;
                const localWidgetVersion = api.getPrefs({
                    sync: true,
                    key: keyWidgetVersion
                });
                // TODO: this is fake remote app version
                const remoteAppVersion = metaData.appVersion;
                if (!remoteAppVersion) {
                    reject(appUpdateError.noRemoteAppVersion);
                    return;
                }
                // TODO: this is fake remote widget version
                const remoteWidgetVersion = metaData.widgetVersion;
                if (!remoteWidgetVersion) {
                    reject(appUpdateError.noRemoteWidgetVersion);
                    return;
                }
                if (localAppVersion != remoteAppVersion) {
                    resolve({
                        'state'     : 'success',
                        'update'    : 'App',
                        'version'   : remoteAppVersion,
                        'url'       : 'APP_URL',
                        'tip'       : 'App更新提示!!',
                        'time'      : 'xxxx-xx-xx'
                    })
                } else if (localWidgetVersion != remoteWidgetVersion) {
                    resolve({
                        'state'     : 'success',
                        'update'    : 'Widget',
                        'version'   : remoteWidgetVersion,
                        'url'       : 'WIDGET_URL',
                        'tip'       : 'Widget更新提示!!',
                        'time'      : 'xxxx-xx-xx'
                    })
                } else {
                    reject(appUpdateError.noUpdate);
                }
            }, 1500);
        });
    }

    /**
     * TODO: test 弹出更新提示框
     * @param {*} metaData 
     * @param {*} callback 
     * @returns 
     */
    function showUpdateDialogPromise(metaData, callback) {
        return new Promise(function(resolve, reject) {
            var str = '新版本号:' + metaData.version + ';\n更新提示语:' + metaData.tip + ';\n下载地址:' + metaData.url + ';\n发布时间:' + metaData.time;
            api.confirm({
                title : '有新的版本,是否下载并安装 ',
                msg : str,
                buttons : ['确定', '取消']
            }, function(ret, err) {
                if (ret.buttonIndex == 1) {
                    resolve({
                        update: metaData.update,
                        url: metaData.url,
                        version: metaData.version
                    });
                    // updateApp({
                    //     'url' : source,
                    //     'appVersion' : appVersion
                    // }, callback);
                } else {
                    reject(appUpdateError.cancelUpdate);
                }
            });
        });
    }

    /**
     * TODO test maybe used next time
     * @param {*} appMetaData 
     * @param {*} callback 
     * @returns 
     */
    function fetchItmsUrlPromise(appMetaData, callback) {
        return new Promise(function(resolve, reject) {
            api.ajax({
                url: source,
                method: 'get',
                data: {
                    '<Key>': '<Value>'
                }
            }, function(ret, err) {
                if (ret) {
                    // api.installApp({
                    //     appUri : '<ipa下载地址>'
                    // });
                    resolve(ret);
                } else {
                    reject(err);
                    // api.alert({ msg: JSON.stringify(err) });
                }
            });
        });
    }

    // function haha() {
    //     console.log('adasdfsada')
    // }

    // function testPromise1() {
    //     return new Promise(function(resolve, reject) {
    //         haha()
    //         resolve('promise 11111')
    //     });
    // }

    // function testPromise2() {
    //     return new Promise(function(resolve, reject) {
    //         // resolve('promise 22222')
    //         reject('iiioooo')
    //     });
    // }

    // function testPromise3() {
    //     return new Promise(function(resolve, reject) {
    //         resolve('promise 3333')
    //     });
    // }

    /** ------------------------- 外部调用 ----------------------- */

    // u.testPromise = function() {
    //     testPromise1()
    //     .then(function(ret) {
    //         console.log('111111111')
    //         console.log(ret)
    //         return testPromise2()
    //     })
    //     .then(function(ret) {
    //         console.log('222222222')
    //         console.log(ret)
    //         return testPromise3()
    //     })
    //     .then(function(ret) {
    //         console.log('333333333')
    //         console.log(ret)
    //     })
    //     .catch(function(err) {
    //         console.log('err')
    //         console.log(err)
    //     })
    // }

    /** ------------------------- 外部调用 ----------------------- */

    /**
     * TODO: test after got api
     * @param {*} metaData 
     * @param {*} callback 
     */
    u.checkUpdate = function(metaData, callback) {
        // check meta data
        checkVersionPromise(metaData, callback)
        .then(function(ret) {
            // if ret get need update else reject
            return showUpdateDialogPromise(ret, callback);
        })
        .then(function(ret) {
            console.log(JSON.stringify(ret))
            if (ret.update === "App") {
                updateAppPromise({
                    url: ret.url
                }, callback);
            } else if (ret.update === "Widget") {
                updateWidgetPromise({
                    url: ret.url,
                    version: ret.version
                }, callback);
            } else {
                errCallbackHandler(appUpdateError.noUpdate, callback);
            }
        })
        .catch(function(err) {
            errCallbackHandler(err, callback);
        })
    }

    /**
     * mock widget update (using promise)
     * @param {*} metadata 
     * @param {*} callback 
     */
    u.checkUpdateWidget = function(metadata, callback) {
        showUpdateDialogPromise({
            'update'    : 'Widget',
            'version'   : metadata.version,
            'url'       : metadata.url,
            'tip'       : 'Widget更新提示!!',
            'time'      : 'xxxx-xx-xx'
        }, callback)
        .then(function(ret) {
            console.log(JSON.stringify(ret))
            updateWidgetPromise(metadata, callback);
        })
        .catch(function(err) {
            errCallbackHandler(err, callback);
        })
    }

    /**
     * mock app update (using promise)
     * @param {*} metadata 
     * @param {*} callback 
     */
    u.checkUpdateApp = function(metadata, callback) {
        showUpdateDialogPromise({
            'update'    : 'App',
            'version'   : metadata.version,
            'url'       : metadata.url,
            'tip'       : 'App更新提示!!',
            'time'      : 'xxxx-xx-xx'
        }, callback)
        .then(function(ret) {
            console.log(JSON.stringify(ret))
            updateAppPromise(metadata, callback);
        })
        .catch(function(err) {
            errCallbackHandler(err, callback);
        })
    }

    window.$appUpdateMan = u;
})(window);
